package com.swf.seed.os.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

public class FTPUtil {


    private FTPClient ftpClient;
    private String _root = "/";
    private String host;
	private int port;
	private String username;
	private String password;


	public void setHost(String host) {
		this.host = host;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

    public void setFtpClient(FTPClient ftpClient) {
		this.ftpClient = ftpClient;
	}

    public FTPUtil() {
    	ftpClient = new FTPClient();
    }

    public boolean connect(String hostname, int port, String username, String password) {
        boolean rs = false;
        try {
            ftpClient.connect(hostname, port);
            ftpClient.setControlEncoding("GBK");
            int replayCode=ftpClient.getReplyCode();
            ftpClient.enterLocalPassiveMode();
            if (FTPReply.isPositiveCompletion(replayCode)) {
                if (ftpClient.login(username, password)) {
                    System.out.println("ftp连接成功。");
                    _root = ftpClient.printWorkingDirectory();
                    System.out.println("_root="+_root);
                    rs = true;
                }else{
                	System.err.println("ftp连接失败。");
                }
            }else{
            	System.err.println("响应码错误,replayCode="+replayCode);
            }
        } catch (Exception e) {
             System.err.println("ftp连接失败:"+e.getMessage());
        }
        return rs;
    }


    public void disconnect() throws IOException {
        if (ftpClient.isConnected()) {
            ftpClient.disconnect();
        }
    }

    public boolean put(String local,String remote) {
        remote = getAbsUnixPath(remote);
        boolean result = false;
        try {
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            String uploadPath = FilenameUtils.separatorsToUnix(FilenameUtils.getFullPath(remote));
            
            if(!exists(uploadPath)&&!mkDir(uploadPath)){
            	System.out.println(String.format("上传目录%s创建失败",uploadPath));
            	return false;
            };
            
            FileInputStream is = new FileInputStream(local);
            try {
            	ftpClient.changeWorkingDirectory(uploadPath);
                result = ftpClient.storeFile(remote, is);
            } finally {
                is.close();
            }
        } catch (Exception e) {
            System.err.println(String.format("上传文件[%s]失败",remote)+e.getMessage());
        }
        return result;
    }
    
    /**
	 * 创建目录
	 * @param filepath 远程文件目录路径
	 * @return
	 * @throws Exception
	 */
	public  boolean mkDir(String remoteDir){
		boolean result = false;
		if (remoteDir==null){
			System.err.println("path can't be null!");
			return false;
		}
		try {
			remoteDir = FilenameUtils.separatorsToUnix(FilenameUtils.normalizeNoEndSeparator(remoteDir));
			if (remoteDir.startsWith("/")){
				//如果是绝对路径并在当前用户根目录下
				if (remoteDir.startsWith(_root)){
					remoteDir = remoteDir.substring(_root.length());
					ftpClient.changeWorkingDirectory(_root);
				}else{
					ftpClient.changeWorkingDirectory("/");//非当前用户目录下
				}
				//删除头部的/
				if (remoteDir.startsWith("/")){
					remoteDir = remoteDir.substring(1);
				}
			}else{
				ftpClient.changeWorkingDirectory(_root);//相对路径，进入用户根目录下
			}
			String parentDir = ftpClient.printWorkingDirectory();
			String[] paths = remoteDir.split("/");
			String currentDirName;
			for (int i = 0; i < paths.length; i++) {
				currentDirName = paths[i];
				String dirPath = FilenameUtils.separatorsToUnix(FilenameUtils.concat(parentDir, currentDirName));
				if (!exists(dirPath)) {
					ftpClient.makeDirectory(currentDirName);
				}
				ftpClient.changeWorkingDirectory(dirPath);
				parentDir = ftpClient.printWorkingDirectory();
			}
			result = true;
		} catch (Exception e) {
			System.err.println("创建目录失败："+e.getMessage());
			result = false;
		}
		return result;
	}
	

    public boolean exists(String remote) {
    	remote = getAbsUnixPath(remote);
        boolean result = false;
        try {
            FTPFile[] files = ftpClient.listFiles(new String(remote.getBytes("GBK"), "iso-8859-1"));
            if (files == null){
            	System.err.println("显示远程文件列表失败，返回结果为null!");
            }else if (files.length == 1) {
                result = true;
            }
        } catch (Exception e) {
            System.err.println("显示远程文件列表失败："+e.getMessage());
        }

        return result;
    }

	public boolean get(String remote, String local) throws IOException {
		remote = getAbsUnixPath(remote);
		ftpClient.enterLocalPassiveMode();
		ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

		FTPFile[] files = ftpClient.listFiles(new String(remote.getBytes("GBK"), "iso-8859-1"));
		if (files == null || files.length != 1) {
			throw new IOException("reomote file does not exist.filename:" + remote);
		}

		File f = null;
		OutputStream out = null;
		boolean fileget = false;
		try {
			f = new File(local);
			out = new FileOutputStream(f);
			fileget = ftpClient.retrieveFile(new String(remote.getBytes("GBK"), "iso-8859-1"), out);
			out.flush();
		} catch (Exception e) {
			System.out.println("file does not exist.filename:" + local);
		} finally {
			if (out != null) {
				out.close();
			}
		}

		return fileget;
	}
    
    
    public boolean renameTo(String oldName, String newName) {
    	oldName = getAbsUnixPath(oldName);
    	return renameFileName(FilenameUtils.getFullPath(oldName), FilenameUtils.getName(oldName), newName);
    }
    
	/**
	 * 重命名远程文件名
	 * @param remoteDir   远程目录
	 * @param oldFileName 原文件名
	 * @param newFileName 新文件名
	 * @return
	 * @throws Exception
	 */
	public boolean renameFileName(String remoteDir, String oldFileName,
			String newFileName) {
		boolean result = false;
		if (!remoteDir.startsWith("/")){
			remoteDir = FilenameUtils.concat(getUserRoot(), remoteDir);
		}
		try {
			// 如果文件已经存在，先删除文件
			if (this.isExist(remoteDir, newFileName)) {
				ftpClient.deleteFile(FilenameUtils.separatorsToUnix(remoteDir+"/"+newFileName));
			}
			// 重命名文件
			String oldFilePath = FilenameUtils.separatorsToUnix(FilenameUtils.concat(remoteDir, oldFileName)); 
			String newFilepath = FilenameUtils.separatorsToUnix(FilenameUtils.concat(remoteDir, newFileName)); 
			System.out.println(String.format("重命名 [%s] 为 [%s]", oldFilePath,newFilepath));
			result =  ftpClient.rename(oldFilePath,newFilepath);
		} catch (Exception e) {
			System.err.println("重命名文件失败");
		}
		return result;
	}  
	/**
	 * 判断指定文件夹下是否存在指定的文件名
	 * @param remoteDir  查找远程根目录
	 * @param fileOrDir 文件或目录名
	 * @return
	 * @throws Exception
	 */
	public  boolean isExist(String remoteDir, String fileOrDir) throws Exception {
		remoteDir = FilenameUtils.separatorsToUnix(remoteDir);
		boolean exist = false;
		try {
			FTPFile[] ls = _list(remoteDir);//列出文件
			//遍历查询文件是否存在
			if (ls != null && ls.length>0) {
				for (int i = 0; i < ls.length; i++) {
					FTPFile f = ls[i];
					String nm = f.getName();
					if (nm.equals(fileOrDir)) {
						exist = true;
						break;
					}
				}
			}
			
		} catch (Exception e) {
			System.err.println("判断文件是否存在异常"+e.getMessage());
		}
		return exist;
	}
	/**
	 * 列出远程目录下的文件
	 * @param dir 远程目录名称
	 * @return
	 */
	private  FTPFile[] _list(String dir) {
		try {
			return ftpClient.listFiles(dir);
		} catch (Exception e) {
			return null;
		}
	}
	private String getAbsUnixPath(String path){
		String result = path;
		if (path==null){
			result=null;
		}
	   	if (!path.startsWith(_root)){
	  		result = FilenameUtils.separatorsToUnix(FilenameUtils.concat(_root, path));
	    }
		return result;
	}
	
	
    public String getUserRoot(){
		return _root;
	}
}